package service

import (
	"context"
	pb "medicine/api/medicine/v1"
	"medicine/internal/biz"
	"medicine/internal/data"
	"net/http"
	"strings"

	"fmt"

	"gorm.io/gorm"

	"github.com/go-kratos/kratos/v2/log"
	kratoshttp "github.com/go-kratos/kratos/v2/transport/http"
)

// AlipayService 支付宝相关接口服务
// 这里只实现回调处理

type AlipayService struct {
	data         *data.DataRepo
	points       *PointsService
	log          *log.Helper
	seckillOrder *biz.SeckillOrderUsecase // 新增字段
}

func NewAlipayService(data *data.DataRepo, points *PointsService, seckillOrder *biz.SeckillOrderUsecase, logger log.Logger) *AlipayService {
	return &AlipayService{
		data:         data,
		points:       points,
		log:          log.NewHelper(logger),
		seckillOrder: seckillOrder,
	}
}

// AlipayNotify 支付宝支付回调处理
func (s *AlipayService) AlipayNotify(w http.ResponseWriter, r *http.Request) {
	s.log.Infof("收到支付宝回调请求")

	if err := r.ParseForm(); err != nil {
		s.log.Errorf("解析表单失败: %v", err)
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("fail"))
		return
	}

	params := make(map[string]string)
	for k, v := range r.PostForm {
		params[k] = strings.Join(v, ",")
	}

	s.log.Infof("支付宝回调参数: %+v", params)

	// 校验签名
	ok, err := s.data.Alipay.VerifyNotify(params)
	if err != nil || !ok {
		s.log.Errorf("支付宝签名验证失败: err=%v, ok=%v", err, ok)
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("fail"))
		return
	}

	s.log.Infof("支付宝签名验证成功")

	// 获取订单号和支付状态
	orderId := params["out_trade_no"]
	tradeStatus := params["trade_status"]

	s.log.Infof("订单号: %s, 交易状态: %s", orderId, tradeStatus)

	if tradeStatus == "TRADE_SUCCESS" || tradeStatus == "TRADE_FINISHED" {
		s.log.Infof("开始处理支付成功回调")

		// 更新订单状态为已支付
		err := s.data.UpdateOrderStatus(context.Background(), orderId, "已支付")
		if err != nil {
			s.log.Errorf("更新订单状态失败: %v", err)
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte("fail"))
			return
		}

		s.log.Infof("订单状态更新成功")

		// 支付成功后扣除MySQL库存
		if err := s.deductMySQLStock(context.Background(), orderId); err != nil {
			s.log.Errorf("扣除MySQL库存失败: %v", err)
			// 注意：库存扣除失败不应该影响支付回调的成功响应
			// 可以通过其他机制补偿处理
		} else {
			s.log.Infof("MySQL库存扣除成功")
		}

		// 支付成功后赠送积分
		if err := s.addPointsForPayment(context.Background(), orderId); err != nil {
			s.log.Errorf("赠送积分失败: %v", err)
			// 注意：积分赠送失败不应该影响支付回调的成功响应
		} else {
			s.log.Infof("积分赠送成功")
		}

		s.log.Infof("支付成功回调处理完成")
	} else {
		s.log.Infof("交易状态不是成功状态，跳过处理")
	}

	w.Write([]byte("success"))
}

// deductMySQLStock 支付成功后扣除MySQL库存
func (s *AlipayService) deductMySQLStock(ctx context.Context, orderNo string) error {
	s.log.Infof("开始扣除MySQL库存，订单号: %s", orderNo)

	// 获取订单信息
	order, err := s.getOrderInfoByOrderNo(ctx, orderNo)
	if err != nil {
		s.log.Errorf("获取订单信息失败: %v", err)
		return err
	}
	if order == nil {
		s.log.Errorf("订单不存在: %s", orderNo)
		return nil
	}

	s.log.Infof("获取到订单信息: ID=%d, SeckillProductID=%d, ProductID=%d, Quantity=%d, Status=%s",
		order.ID, order.SeckillProductID, order.ProductID, order.Quantity, order.Status)

	// 检查秒杀商品是否存在
	var seckillProduct biz.SeckillProduct
	err = s.data.DB.WithContext(ctx).First(&seckillProduct, order.SeckillProductID).Error
	if err != nil {
		s.log.Errorf("查询秒杀商品失败，秒杀商品ID=%d: %v", order.SeckillProductID, err)
		return err
	}

	s.log.Infof("秒杀商品信息: ID=%d, ProductID=%d, 当前秒杀库存=%d",
		seckillProduct.ID, seckillProduct.ProductID, seckillProduct.SeckillStock)

	// 扣除MySQL中的秒杀商品库存
	err = s.data.DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		s.log.Infof("开始数据库事务，扣减秒杀库存: 秒杀商品ID=%d, 数量=%d", order.SeckillProductID, order.Quantity)

		// 扣减秒杀商品库存
		res := tx.Model(&biz.SeckillProduct{}).
			Where("id = ? AND seckill_stock >= ?", order.SeckillProductID, order.Quantity).
			Update("seckill_stock", gorm.Expr("seckill_stock - ?", order.Quantity))

		s.log.Infof("秒杀库存扣减SQL执行结果: RowsAffected=%d, Error=%v", res.RowsAffected, res.Error)

		if res.RowsAffected == 0 {
			return fmt.Errorf("秒杀商品库存不足或不存在，秒杀商品ID=%d，需要数量=%d，当前库存=%d",
				order.SeckillProductID, order.Quantity, seckillProduct.SeckillStock)
		}
		return nil
	})

	if err != nil {
		s.log.Errorf("扣除MySQL秒杀库存失败，订单号=%s，秒杀商品ID=%d，数量=%d，错误=%v",
			orderNo, order.SeckillProductID, order.Quantity, err)
		return err
	}

	// 验证库存变化
	var updatedSeckillProduct biz.SeckillProduct
	err = s.data.DB.WithContext(ctx).First(&updatedSeckillProduct, order.SeckillProductID).Error
	if err != nil {
		s.log.Errorf("查询更新后的秒杀商品失败: %v", err)
	} else {
		s.log.Infof("秒杀库存扣减验证: 原库存=%d, 新库存=%d, 减少=%d",
			seckillProduct.SeckillStock, updatedSeckillProduct.SeckillStock, seckillProduct.SeckillStock-updatedSeckillProduct.SeckillStock)
	}

	s.log.Infof("支付成功后扣除MySQL秒杀库存成功，订单号=%s，秒杀商品ID=%d，数量=%d",
		orderNo, order.SeckillProductID, order.Quantity)
	return nil
}

// addPointsForPayment 支付成功后赠送积分
func (s *AlipayService) addPointsForPayment(ctx context.Context, orderNo string) error {
	// 用订单编号查询订单
	order, err := s.getOrderInfoByOrderNo(ctx, orderNo)
	if err != nil {
		s.log.Errorf("获取订单信息失败: %v", err)
		return err
	}
	if order == nil {
		s.log.Errorf("订单不存在: %s", orderNo)
		return nil
	}
	amount := float64(order.SeckillPrice) * float64(order.Quantity)
	req := &pb.AddPointsForConsumptionRequest{
		UserId:    order.UserID,
		OrderId:   order.ID, // 用数据库ID
		Amount:    amount,
		OrderType: "seckill_order",
	}
	_, err = s.points.AddPointsForConsumption(ctx, req)
	if err != nil {
		s.log.Errorf("赠送积分失败: %v", err)
		return err
	}
	return nil
}

// getOrderInfoByOrderNo 用订单编号查询订单
func (s *AlipayService) getOrderInfoByOrderNo(ctx context.Context, orderNo string) (*biz.SeckillOrder, error) {
	return s.seckillOrder.GetByOrderNo(ctx, orderNo)
}

// AlipayNotifyKratos 适配 go-kratos http.Handler
func (s *AlipayService) AlipayNotifyKratos(ctx kratoshttp.Context) error {
	req := ctx.Request()
	res := ctx.Response()
	s.AlipayNotify(res, req)
	return nil
}
